﻿using System;
using System.Windows;
using System.Windows.Media;
using nRoute.Components.Composition;
using nRoute.Utilities;

namespace nRoute.ViewServices
{
    public class DiscoveredInstanceLifetimeManager
        : ILifetimeManager
    {
        private readonly Type _viewServiceElementType;
        private readonly string _viewServiceElementName;

        public DiscoveredInstanceLifetimeManager(string viewServiceElementName)
            : this(null, viewServiceElementName) { }

        public DiscoveredInstanceLifetimeManager(Type viewServiceElementType)
            : this(viewServiceElementType, null) { }

        public DiscoveredInstanceLifetimeManager(Type viewServiceElementType, string viewServiceElementName)
        {
            _viewServiceElementType = viewServiceElementType;
            _viewServiceElementName = viewServiceElementName;
        }

        public Type ViewServiceElementType
        {
            get { return _viewServiceElementType; }
        }

        public string ViewServiceElementName
        {
            get { return _viewServiceElementName; }
        }

#region ILifetimeManager Related

        public object ManageBuild(ITypeBuilder typeBuilder, Func<ITypeBuilder, object> resourceBuilder)
        {
            // we search in the application's visual tree 
            var _viewServiceElement = default(DependencyObject);
#if SILVERLIGHT
            return (GetViewServiceElement(Application.Current.RootVisual, out _viewServiceElement)) ? _viewServiceElement : null;
#elif WINRT
            return (GetViewServiceElement(Window.Current.Content, out _viewServiceElement)) ? _viewServiceElement : null;
#else
            return (GetViewServiceElement(Application.Current.MainWindow, out _viewServiceElement)) ? _viewServiceElement : null;
#endif
        }

        protected virtual void Dispose(bool disposing) { }

#endregion

#region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

#endregion

#region Helpers

        private bool GetViewServiceElement(DependencyObject element, out DependencyObject viewServiceElement)
        {
            // by default
            viewServiceElement = null;

            // we check if the given element is the implementation type we are looking for
            if (element == null)
            {
                return false;
            }

            if (!string.IsNullOrWhiteSpace(this.ViewServiceElementName) && this.ViewServiceElementType != null)
            {
                if (string.Equals(this.ViewServiceElementName, Convert.ToString(element.GetValue(FrameworkElement.NameProperty)), Utilities.Compatability.INVARIANT_IGNORECASE_STRING_COMPARISION)
                    && this.ViewServiceElementType == element.GetType())
                {
                    viewServiceElement = element;
                    return true;
                }
            }
            else if (!string.IsNullOrWhiteSpace(this.ViewServiceElementName))
            {
                if (string.Equals(this.ViewServiceElementName, Convert.ToString(element.GetValue(FrameworkElement.NameProperty)), Utilities.Compatability.INVARIANT_IGNORECASE_STRING_COMPARISION))
                {
                    viewServiceElement = element;
                    return true;
                }
            }
            else if (this.ViewServiceElementType != null)
            {
                if (this.ViewServiceElementType == element.GetType())
                {
                    viewServiceElement = element;
                    return true;
                }
            }

            // else we check it's children
            var _childCount = VisualTreeHelper.GetChildrenCount(element);
            if (_childCount == 0) return false;

            // we check each element's child
            for (int i = 0; i < _childCount; i++)
            {
                if (GetViewServiceElement(VisualTreeHelper.GetChild(element, i), out viewServiceElement))
                {
                    return true;
                }
            }

            // all else
            return false;
        }

#endregion

    }
}